package main

import (
    "gitee.com/mayiweb/gohs"
)

// 获得行情请求编号
func (p *HsMdSpi) GetMdRequestId() int {
    Ctp.MdRequestId += 1
    return Ctp.MdRequestId
}

// 获得 API 错误信息
func (p *HsMdSpi) GetApiErrorMsg(iResult int) string {
    return GbkToUtf8(Ctp.MdApi.GetApiErrorMsg(iResult))
}

// 行情系统错误通知
func (p *HsMdSpi) IsErrorRspInfo(pRspInfo gohs.CHSRspInfoField) bool {

    // 容错处理 pRspInfo ，部分响应函数中，pRspInfo 为空
    if IsNullPointer(pRspInfo) {

        return false

    } else {

        ErrorID := GetSwigInt32(pRspInfo.GetErrorID())

        // 如果ErrorID != 0, 说明收到了错误的响应
        bResult := (ErrorID != 0)
        if bResult {
            LogPrintf("ErrorID=%v ErrorMsg=%v\n", ErrorID, GbkToUtf8(pRspInfo.GetErrorMsg()))
        }

        return bResult
    }
}

// 发送请求日志（仅查询类的函数需要调用）
func (p *HsMdSpi) ReqMsg(Msg string) {

    // 交易程序未初始化完成时，执行查询类的函数需要有1.5秒间隔，恒生无此限制
    if !Ctp.IsTradeInitFinish {
        // Sleep(1500)
    }

    Println("")
    LogPrintln(Msg)
}

// 发送请求失败日志
func (p *HsMdSpi) ReqFailMsg(Msg string, iResult int) {
    Printf("%v [%d: %s]\n", Msg, iResult, p.GetApiErrorMsg(iResult))
}

// 当客户端与交易后台通信连接断开时，该方法被调用。当发生这个情况后，API会自动重新连接，客户端可不做处理。
// 服务器已断线，该函数也会被调用。【api 会自动初始化程序，并重新登陆】
func (p *HsMdSpi) OnFrontDisconnected(nReason int) {

    if Ctp.IsMdInit {

        Ctp.IsMdInit  = false

        LogPrintln("行情服务器已断线，尝试重新连接中...")
    }
}

// 当客户端与交易后台建立起通信连接时（还未登录前），该方法被调用。
func (p *HsMdSpi) OnFrontConnected() {

    InitStr := "-------------------------------------------------------------------------------------------------\n" +
                 "- 行情系统初始化成功，API 版本：" + gohs.GetMdApiVersion() + "\n" +
                 "-------------------------------------------------------------------------------------------------"
    Println(InitStr)

    Ctp.IsMdInit = true
}

// 行情订阅
func (p *HsMdSpi) SubscribeMarketData(InstrumentIDs []string) int {

    if len(InstrumentIDs) == 0 {
        LogPrintln("没有指定需要订阅的行情数据")
        return 0
    }

    LogPrintln(Sprintf("订阅 %v 个行情 %v", len(InstrumentIDs), InstrumentIDs))

    // 批量发送订阅 会返回很多无用行情，只能单个发送

    iResult := 0
    for _, v := range InstrumentIDs {

        RequestId := p.GetMdRequestId()

        ExchangeID := "1"

        Instrument, InstrumentOk := GetInstrumentInfo(v)
        if InstrumentOk {
            ExchangeID = Instrument.ExchangeID
        }

        req := gohs.NewCHSReqDepthMarketDataField()
        req.SetExchangeID(ExchangeID)
        req.SetInstrumentID(v)

        iResult = Ctp.MdApi.ReqDepthMarketDataSubscribe(req, 1, RequestId)
        if iResult != SDK_OK {
            p.ReqFailMsg("发送行情订阅请求失败！", iResult)
        }

        MapMdRequests.Set(RequestId, v)
    }

    return iResult
}

// 行情订阅响应
func (p *HsMdSpi) OnRspDepthMarketDataSubscribe(pRspInfo gohs.CHSRspInfoField, nRequestID int, bIsLast bool) {

    if bIsLast && !p.IsErrorRspInfo(pRspInfo) {
        // mRequestVal, mRequestOk := MapMdRequests.Get(nRequestID)
        // if !mRequestOk {
        //     LogPrintln("行情订阅成功")
        // }
        // LogPrintf("订阅合约 %v 行情数据成功！\n", mRequestVal)
    }
}

// 取消行情订阅
func (p *HsMdSpi) SubscribeMarketDataCancel(InstrumentID string) {

    ExchangeID := "1"

    Instrument, InstrumentOk := GetInstrumentInfo(InstrumentID)
    if InstrumentOk {
        ExchangeID = Instrument.ExchangeID
    }

    req := gohs.NewCHSReqDepthMarketDataField()
    req.SetExchangeID(ExchangeID)
    req.SetInstrumentID(InstrumentID)

    iResult := Ctp.MdApi.ReqDepthMarketDataCancel(req, 1, p.GetMdRequestId())
    if iResult != SDK_OK {
        p.ReqFailMsg("发送取消订阅行情请求失败！", iResult)
    }
}

// 取消行情订阅响应
func (p *HsMdSpi) OnRspDepthMarketDataCancel(pRspInfo gohs.CHSRspInfoField, nRequestID int, bIsLast bool) {

    if bIsLast && !p.IsErrorRspInfo(pRspInfo) {
        Println("取消订阅行情成功")
    }
}

// 深度行情响应
func (p *HsMdSpi) OnRtnDepthMarketData(pDepthMarketData gohs.CHSDepthMarketDataField) {

    defer CheckPanic()

    if !IsNullPointer(pDepthMarketData) {

        var MarketData MarketDataStruct

        MarketData.TradingDay            = Int32ToString(GetSwigInt32(pDepthMarketData.GetTradingDay()))
        MarketData.InstrumentID          = string(pDepthMarketData.GetInstrumentID())
        MarketData.ExchangeID            = string(pDepthMarketData.GetExchangeID())
        MarketData.LastPrice             = Decimal(pDepthMarketData.GetLastPrice(), 4)
        MarketData.PreSettlementPrice    = Decimal(pDepthMarketData.GetPreSettlementPrice(), 4)
        MarketData.PreClosePrice         = Decimal(pDepthMarketData.GetPreClosePrice(), 4)
        MarketData.OpenPrice             = Decimal(pDepthMarketData.GetOpenPrice(), 4)
        MarketData.HighestPrice          = Decimal(pDepthMarketData.GetHighestPrice(), 4)
        MarketData.LowestPrice           = Decimal(pDepthMarketData.GetLowestPrice(), 4)
        MarketData.Volume                = int(pDepthMarketData.GetTradeVolume())
        MarketData.TradeBalance          = Decimal(pDepthMarketData.GetTradeBalance(), 4)
        MarketData.OpenInterest          = int(pDepthMarketData.GetOpenInterest())
        MarketData.ClosePrice            = Decimal(pDepthMarketData.GetClosePrice(), 4)
        MarketData.SettlementPrice       = Decimal(pDepthMarketData.GetSettlementPrice(), 4)
        MarketData.UpperLimitPrice       = Decimal(pDepthMarketData.GetUpperLimitPrice(), 4)
        MarketData.LowerLimitPrice       = Decimal(pDepthMarketData.GetLowerLimitPrice(), 4)
        MarketData.PreDelta              = pDepthMarketData.GetPreDelta()
        MarketData.CurrDelta             = pDepthMarketData.GetCurrDelta()
        MarketData.UpdateTime            = HsTime(Int32ToString(GetSwigInt32(pDepthMarketData.GetUpdateTime())))
        MarketData.BidPrice1             = Decimal(pDepthMarketData.GetBidPrice1(), 4)
        MarketData.BidVolume1            = int(pDepthMarketData.GetBidVolume1())
        MarketData.AskPrice1             = Decimal(pDepthMarketData.GetAskPrice1(), 4)
        MarketData.AskVolume1            = int(pDepthMarketData.GetAskVolume1())
        MarketData.BidPrice2             = Decimal(pDepthMarketData.GetBidPrice2(), 4)
        MarketData.BidVolume2            = int(pDepthMarketData.GetBidVolume2())
        MarketData.AskPrice2             = Decimal(pDepthMarketData.GetAskPrice2(), 4)
        MarketData.AskVolume2            = int(pDepthMarketData.GetAskVolume2())
        MarketData.BidPrice3             = Decimal(pDepthMarketData.GetBidPrice3(), 4)
        MarketData.BidVolume3            = int(pDepthMarketData.GetBidVolume3())
        MarketData.AskPrice3             = Decimal(pDepthMarketData.GetAskPrice3(), 4)
        MarketData.AskVolume3            = int(pDepthMarketData.GetAskVolume3())
        MarketData.BidPrice4             = Decimal(pDepthMarketData.GetBidPrice4(), 4)
        MarketData.BidVolume4            = int(pDepthMarketData.GetBidVolume4())
        MarketData.AskPrice4             = Decimal(pDepthMarketData.GetAskPrice4(), 4)
        MarketData.AskVolume4            = int(pDepthMarketData.GetAskVolume4())
        MarketData.BidPrice5             = Decimal(pDepthMarketData.GetBidPrice5(), 4)
        MarketData.BidVolume5            = int(pDepthMarketData.GetBidVolume5())
        MarketData.AskPrice5             = Decimal(pDepthMarketData.GetAskPrice5(), 4)
        MarketData.AskVolume5            = int(pDepthMarketData.GetAskVolume5())
        MarketData.AveragePrice          = Decimal(pDepthMarketData.GetAveragePrice(), 4)
        MarketData.PreOpenInterest       = pDepthMarketData.GetPreOpenInterest()
        MarketData.InstrumentTradeStatus = string(pDepthMarketData.GetInstrumentTradeStatus())
        MarketData.OpenRestriction       = pDepthMarketData.GetOpenRestriction()

        p.MarketData(MarketData)
    }
}

// 深度行情
func (p *HsMdSpi) MarketData(pMarketData MarketDataStruct) {

    // 未开盘的行情 金额太长，直接过滤 1.7976931348623157e+308
    if pMarketData.BidPrice1 == 1.7976931348623157e+308 || pMarketData.AskPrice1 == 1.7976931348623157e+308 || pMarketData.OpenPrice == 1.7976931348623157e+308 {
        return
    }

    // 有一些为0的垃圾数据，此处过滤
    if pMarketData.Volume == 0 && pMarketData.BidPrice1 == 0.00 && pMarketData.AskPrice1 == 0.00 && pMarketData.BidVolume1 == 0 && pMarketData.AskVolume1 == 0 || pMarketData.LastPrice == 0 {
        return
    }

    // 获得合约详情
    Instrument, _ := GetInstrumentInfo(pMarketData.InstrumentID)

    pMarketData.InstrumentName = Instrument.InstrumentName

    // 注意：如果涨停，卖一价没有报价会为0
    if pMarketData.BidPrice1 == 0.00 {
        pMarketData.BidPrice1 = pMarketData.LastPrice
    }

    // 注意：如果跌停，买一价没有报价会为0
    if pMarketData.AskPrice1 == 0.00 {
        pMarketData.AskPrice1 = pMarketData.LastPrice
    }

    Printf("%v \t最新价 %v \t买一 %v \t卖一 %v \t成交量 %v \t持仓 %v \n", pMarketData.InstrumentID, pMarketData.LastPrice, pMarketData.BidPrice1, pMarketData.AskPrice1, pMarketData.Volume, pMarketData.OpenInterest)
}